<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="F6Et0" id="F6Et0"><span data-lake-id="u73876430" id="u73876430">典型回答</span></h1>
  <p data-lake-id="ud6d86697" id="ud6d86697"><span data-lake-id="ua55ba819" id="ua55ba819">​</span><br></p>
  <blockquote data-lake-id="uafc7e828" id="uafc7e828">
   <p data-lake-id="u57436ba4" id="u57436ba4"><span data-lake-id="u47102f38" id="u47102f38">在序列化过程中，如果被序列化的类中定义了writeObject 和 readObject 方法，虚拟机会试图调用对象类里的 writeObject 和 readObject 方法，进行用户自定义的序列化和反序列化。</span></p>
   <p data-lake-id="udfb5bc4c" id="udfb5bc4c"><span data-lake-id="u72bf31b6" id="u72bf31b6">如果没有这样的方法，则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。</span></p>
   <p data-lake-id="u399712e7" id="u399712e7"><span data-lake-id="ub82e4d6d" id="ub82e4d6d">用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程，比如可以在序列化的过程中动态改变序列化的数值。</span></p>
  </blockquote>
  <p data-lake-id="u91214a15" id="u91214a15"><span data-lake-id="u2d629ddf" id="u2d629ddf">​</span><br></p>
  <p data-lake-id="u93162d23" id="u93162d23" style="text-align: justify"><span data-lake-id="ub0fd73ec" id="ub0fd73ec">ArrayList底层是通过Object数组完成数据存储的，但是这个数组被声明成了 transient，说明在默认的序列化策略中并没有序列化数组字段。</span></p>
  <p data-lake-id="u41089f1d" id="u41089f1d" style="text-align: justify"><span data-lake-id="ue57dd330" id="ue57dd330">​</span><br></p>
  <p data-lake-id="u0668c740" id="u0668c740" style="text-align: justify"><span data-lake-id="ua8bbaa6c" id="ua8bbaa6c">ArrayList重写了writeObject和readObject方法，如下所示：</span></p>
  <pre lang="java"><code>
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;

    // Read in size, and any hidden stuff
    s.defaultReadObject();

    // Read in capacity
    s.readInt(); // ignored

    if (size &gt; 0) {
        // be like clone(), allocate array based upon size not capacity
        ensureCapacityInternal(size);

        Object[] a = elementData;
        // Read in all elements in the proper order.
        for (int i=0; i&lt;size; i++) {
            a[i] = s.readObject();
        }
    }
}
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    s.defaultWriteObject();

    // Write out size as capacity for behavioural compatibility with clone()
    s.writeInt(size);

    // Write out all elements in the proper order.
    for (int i=0; i&lt;size; i++) {
        s.writeObject(elementData[i]);
    }

    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}
</code></pre>
  <p data-lake-id="ud6c0a160" id="ud6c0a160"><br></p>
  <h1 data-lake-id="lyxj2" id="lyxj2"><span data-lake-id="u28caf4d2" id="u28caf4d2">知识扩展</span></h1>
  <h2 data-lake-id="Qb2zV" id="Qb2zV"><span data-lake-id="u18c518cc" id="u18c518cc">为什么底层数组要使用transient</span></h2>
  <p data-lake-id="uaa196f64" id="uaa196f64"><span data-lake-id="u885c4a15" id="u885c4a15">ArrayList实际上是动态数组，每次在放满以后自动增长设定的长度值，如果数组自动增长长度设为100，而实际只放了一个元素，那就会序列化99个null元素。为了保证在序列化的时候不会将这么多null同时进行序列化，ArrayList把元素数组设置为transient。</span></p>
  <p data-lake-id="uc905141b" id="uc905141b"><span data-lake-id="u57389a75" id="u57389a75">​</span><br></p>
  <p data-lake-id="u9e2fe8d6" id="u9e2fe8d6"><span data-lake-id="ua1db86cf" id="ua1db86cf">所以，为了避免Java自带的序列化机制造成的空间浪费，把数组定义为transient，然后重写writeObject和readObject来实现序列化操作。</span></p>
 </body>
</html>